package com.alpaca.recommend.service;

import com.alpaca.recommend.bean.*;
import com.alpaca.recommend.dto.Constants;
import com.alpaca.recommend.dto.UserItemDTO;
import com.alpaca.recommend.util.MD5Util;
import com.alpaca.recommend.util.Paged;
import com.alpaca.recommend.util.SpringContextLoader;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by wangj on 2015/2/10.
 */
@Service
public class URecommendService {


    public static final int DEFAULT_THRESHOLD = 3;
    public static final String DEFAULT_USER_ID = "0";
    public static final String SPLIT = ",";
    private static Logger logger = LoggerFactory.getLogger(URecommendService.class);

    private  class InnerExec {
        public void pre(StringBuilder sb) {}
        public void after(StringBuilder sb) {}
    }

    public void execCommon(String channelCode , String userId , String itemId , InnerExec innerExec) {
        String rowKey = getRowKey(channelCode, userId);
        URecommend recommend = URecommend.dao.get(rowKey);
        if (recommend == null) {
            return;
        }
        String ids = recommend.getString(URecommend.RANK , URecommend.IDS);
        String[] idArray = ids.split(SPLIT);
        StringBuilder sb = new StringBuilder();
        innerExec.pre(sb);
        for (String id : idArray) {
            if (id.equals(itemId)) {
                continue;
            }
            sb.append(id).append(SPLIT);
        }
        innerExec.after(sb);
        recommend.saveRecommend(rowKey, sb.toString());
    }

    public void delete(String channelCode , String userId , String itemId) {
        execCommon(channelCode,userId,itemId , new InnerExec());
    }

    public void setToTail(String channelCode , String userId , final String itemId) {
        execCommon(channelCode, userId, itemId, new InnerExec() {
            public void after(StringBuilder sb) {
                sb.append(itemId);
            }
        });
    }

    public void setToFirst(String channelCode , String userId ,final String itemId) {
        execCommon(channelCode, userId, itemId, new InnerExec() {
            public void pre(StringBuilder sb) {
                sb.append(itemId).append(SPLIT);
            }
        });
    }


    /**
     * 在用户推荐量小于3的情况下使用该频道的默认推荐推送,并覆盖用户当天推荐
     * 分页查询id列表
     * @param pageNo
     * @param pageSize
     * @param channelCode
     * @param userId
     * @return
     */
    public Paged<Integer> findByPage(String channelCode , String userId ,Integer pageNo , Integer pageSize ) {
        String rowKey = getRowKey(channelCode, userId);
        URecommend uRecommends = URecommend.dao.get(rowKey);
        String ids ;
        //预先获取已缓存到表的数据
        if (uRecommends != null) {
            ids = (uRecommends.getString(URecommend.RANK , URecommend.IDS));
        }else {
            ids = resetRecommendItems(channelCode ,userId);
        }

        List<Integer> list = new ArrayList<Integer>();
        if (StringUtils.isEmpty(ids)) {
            return new Paged<Integer>(list ,0 , pageNo ,pageSize);
        }

        String[] idParts = ids.split(SPLIT);

        //当小于阀值时,使用该频道下默认的推荐去覆盖
        if (idParts.length < DEFAULT_THRESHOLD) {
            String defaultRowKey = getRowKey(channelCode , DEFAULT_USER_ID);
            URecommend recommend = URecommend.dao.get(defaultRowKey);
            if (recommend == null) {
                logger.error("频道:"+channelCode+"下无默认推荐,请处理!");
                return new Paged<Integer>(list ,0 , pageNo ,pageSize);
            }

            String defaultIds = recommend.getString(URecommend.RANK, URecommend.IDS);
            idParts = defaultIds.split(SPLIT);
            recommend.saveRecommend(rowKey , defaultIds);
        }

        int start = (pageNo - 1) * pageSize;
        int end = pageNo * pageSize;
        end = end < idParts.length ? end : idParts.length;

        for (int i = start ; i< end ; i++) {
            list.add( Integer.valueOf(idParts[i]) );
        }

        return new Paged<Integer>(list ,idParts.length,pageNo,pageSize);
    }

    private String getRowKey(String channelCode, String userId) {
        return MD5Util.md5(userId) +  MD5Util.md5(channelCode);
    }

    /**
     * 推荐
     * @param channelCode
     * @param userId
     * @return
     */
    public String resetRecommendItems(String channelCode , String userId) {
        String rowKey = getRowKey(channelCode, userId);

        //不存在时从item表获取积分,并根据积分排序
        List<UItem> itemsList = UItem.dao.findByPrefix(rowKey);

        if (itemsList.size() == 0) {
            return "";
        }

        List<UserItemDTO> dtos = new ArrayList<UserItemDTO>();
        for (UItem item : itemsList) {
            //跳过已阅读的文章
            Integer flag = 2;
            if (item.getInt("i" , "ir") == 1) {
                flag = 1;
            }

            dtos.add(new UserItemDTO(item.getRowKey().replace(rowKey , "") , item.getInt("i" , "r") * flag));
        }

        Collections.sort(dtos ,new Comparator<UserItemDTO>() {
            @Override
            public int compare(UserItemDTO o1, UserItemDTO o2) {
                return o2.getRank() - o1.getRank() ;
            }
        });
        StringBuilder sb = new StringBuilder();
        for (UserItemDTO dto : dtos) {
            sb.append(dto.getItemId()).append(",");
        }
        String ids = sb.substring(0 ,sb.length() - 1);
        //保存到缓存表中
        URecommend uRecommends  = new URecommend();
        uRecommends.setRow(rowKey).set(URecommend.RANK,URecommend.IDS , ids).save();

        return ids;
    }


    public boolean add(String channelcode,String userId,String itemId){
        //保存用户
        User user = new User();
        user.init(userId);
        user.save();
        //更新u_items已读状态
        UItem uItem = new UItem();
        uItem.init(channelcode,userId,itemId,1);
        uItem.save();
        //将文章放置导推荐列表末尾
        setToTail(channelcode,userId,itemId);
        //保存u_tags
        Item item = new Item();
        item.get(itemId);
        String tagstir = item.getString(Item.ITEMS_I_FAMILY,Item.ITEMS_I_TAG);
        String[] tags = tagstir.split(Constants.SEPARATE_COMMA);
        for(String tag:tags){
            UTags uTags = new UTags();
            uTags.get(UTags.getRowKey(channelcode, userId, tag));
            int orginRank = 0;
            int orginCount = 0;
            if(uTags.exists()){
                orginRank = uTags.getInt(UTags.U_TAGS_FAMILY,UTags.U_TAGS_T_RANK);
                orginCount = uTags.getInt(UTags.U_TAGS_FAMILY,UTags.U_TAGS_T_COUNT);
                uTags.init(channelcode,userId,tag,orginRank+1,orginCount+1);
                //TODO 需要处理更新失败的场景
                boolean success = uTags.checkAndPut(UTags.getRowKey(channelcode, userId, tag),
                        UTags.U_TAGS_FAMILY,
                        UTags.U_TAGS_T_RANK,
                        orginRank);
            }else {
                UTags saveUTags = new UTags();
                saveUTags.init(channelcode,userId,tag,orginRank+1,orginCount+1);
                saveUTags.save();
            }
            //保存导tag_user 暂无更多处理
            TagUser tagUser = new TagUser();
            tagUser.init(channelcode,userId,tag);
            tagUser.save();
        }

        return true;
    }

    public static void main(String[] args) {
        SpringContextLoader.init();
        String rowKey = MD5Util.md5("1") +  MD5Util.md5("90022") ;
        URecommendService uRecommendService = SpringContextLoader.getBean(URecommendService.class);
        uRecommendService.setToFirst("90022" , "1", "3");
        uRecommendService.setToTail("90022", "1", "2");
        uRecommendService.delete("90022", "1", "2");

        System.out.println(URecommend.dao.get(rowKey).getString("r", "ids"));
        System.exit(0);
    }
}
